﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ESpace;

namespace ESpace_Project
{
    public partial class FormLabirynth : Form
    {
        class Cell
        {
            public bool obs;
            public bool light = false; // освещена
            public bool lp; // освещена другим источником
            public Cell(bool obs)
            {
                this.obs = obs;
            }
        }

        int step = 10;
        int prcFill = 10; // процент заполнения поля
        Cell[,] mtr;
        int w;
        int h;
        Graphics gr;
        Random rnd = new Random();
        Point pl;
        int R = 5;

        public FormLabirynth()
        {
            InitializeComponent();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            im.Image = new Bitmap(im.Width, im.Height);
            gr = Graphics.FromImage(im.Image);
            w = im.Width / step;
            h = im.Height / step;
            mtr = new Cell[w, h];
            for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                {
                    mtr[i, j] = new Cell(false);
                }

            // рандомное расставление препятствий
            for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                {
                    mtr[i, j] = new Cell(rnd.Next(100) < prcFill);
                }

            // расстановка освещения другим источником
             for (int i = 0; i < 5; i++)
                 for (int j = 0; j < 5; j++)
                         mtr[i, j].lp = true;


            // установка позиции плеера
            pl = new Point(10, 10);
            mtr[10, 10] = new Cell(false);
            //pl = new Point(rnd.Next(w), rnd.Next(h));
            //pl = new Point(w / 2, h / 2);

            DrawAll();
        }

        void DrawAll()
        {
            gr.Clear(Color.Gray);

            // клетки
            for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                {
                    if (mtr[i, j].obs)
                    {
                        if (mtr[i, j].light) gr.FillRectangle(Brushes.Blue, i * step, j * step, step, step);
                        else gr.FillRectangle(Brushes.Black, i * step, j * step, step, step);
                    }
                    else
                    {
                        if (mtr[i, j].light) gr.FillRectangle(Brushes.White, i * step, j * step, step, step);
                        else gr.FillRectangle(Brushes.Gray, i * step, j * step, step, step);
                    }

                    if (step > 3) gr.DrawRectangle(Pens.Black, i * step, j * step, step, step);
                }

            // освещенная область
            DateTime dt = DateTime.Now;
            double fps = 0;
            List<Point> p = new List<Point>();
            for(int i=0;i<1;i++)
                p = Labyrinth.LightRange(pl.X, pl.Y, R, 270, 100, IsObstracle, IsLighting, w, h);
            fps = 1/(DateTime.Now - dt).TotalSeconds;

            for (int i = 0; i < p.Count; i++)
            {
                if (mtr[p[i].X, p[i].Y].obs)
                    gr.FillRectangle(Brushes.Blue, p[i].X * step, p[i].Y * step, step, step);
                else
                    gr.FillRectangle(Brushes.White, p[i].X * step, p[i].Y * step, step, step);
                if (step > 3) gr.DrawRectangle(Pens.Black, p[i].X * step, p[i].Y * step, step, step);
            }

            // освещение другими источниками
            SolidBrush brLight = new SolidBrush(Color.FromArgb(70, 255, 240, 0));
            for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                {
                    if (mtr[i, j].lp) gr.FillRectangle(brLight, i * step, j * step, step, step);
                }
            brLight.Dispose();

            // плеер
            gr.FillRectangle(Brushes.Green, pl.X * step, pl.Y * step, step, step);
            gr.DrawRectangle(Pens.Black, pl.X * step, pl.Y * step, step, step);

            // поиск дубликатов в лайт-поинтах
            List<Point> p1 = new List<Point>();
            for (int i = 0; i < p.Count; i++)
            {
                for (int j = i + 1; j < p.Count; j++)
                    if (p[i] == p[j]) p1.Add(p[i]);
            }
            for (int i = 0; i < p1.Count; i++)
            {
                gr.FillRectangle(Brushes.Red, p[i].X * step + 2, p[i].Y * step + 2, step - 4, step - 4);
            }

            /*if (Labyrinth.fldW != null)
            {
                for (int i = 0; i < w; i++)
                    for (int j = 0; j < h; j++)
                    {
                        gr.DrawString(Labyrinth.fldW[i, j].ToString(), Font, Brushes.Red, i * step, j * step);
                    }
            }*/


            im.Refresh();

            Text = "Радиус:" + R.ToString() + " FPS:" + fps.ToString();
        }

        bool IsObstracle(int x, int y)
        {
            return mtr[x, y].obs;
        }

        bool IsLighting(int x, int y)
        {
            return mtr[x, y].lp;
        }

        private void im_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            Point lastPl = pl;
            if (e.KeyCode == Keys.Up)
            {
                if (pl.Y > 0)
                    if (!mtr[pl.X, pl.Y - 1].obs) pl.Y--;
            }
            if (e.KeyCode == Keys.Down)
            {
                if (pl.Y < (h - 1))
                    if (!mtr[pl.X, pl.Y + 1].obs) pl.Y++;
            }
            if (e.KeyCode == Keys.Left)
            {
                if (pl.X > 0)
                    if (!mtr[pl.X - 1, pl.Y].obs) pl.X--;
            }
            if (e.KeyCode == Keys.Right)
            {
                if (pl.X < (w - 1))
                    if (!mtr[pl.X + 1, pl.Y].obs) pl.X++;
            }
            if (e.KeyCode == Keys.PageUp)
            {
                R++;
                DrawAll();
            }
            if (e.KeyCode == Keys.PageDown)
            {
                if (R > 0) R--;
                DrawAll();
            }

            if (lastPl != pl) DrawAll();
        }

        List<TrackAction> trl = new List<TrackAction>();
        List<TrackAction8> trl8 = new List<TrackAction8>();

        bool IsObs(int x, int y)
        {
            return mtr[x, y].obs;
        }

        private void im_MouseDown(object sender, MouseEventArgs e)
        {
            int x = e.X/step;
            int y = e.Y/step;
            trl8 = Labyrinth.SearchWave8(Labyrinth.GenFldObs(w, h, IsObs), pl.X, pl.Y, x, y);
            tmrMove.Start();
        }

        private void tmrMove_Tick(object sender, EventArgs e)
        {
            if (trl.Count == 0 && trl8.Count==0)
            {
                tmrMove.Stop();
                return;
            }

            if (trl.Count > 0)
            {
                if (trl[0] == TrackAction.moveUp) pl.Y--;
                if (trl[0] == TrackAction.moveDown) pl.Y++;
                if (trl[0] == TrackAction.moveLeft) pl.X--;
                if (trl[0] == TrackAction.moveRight) pl.X++;
                trl.RemoveAt(0);
            }
            else
            {
                if (trl8[0] == TrackAction8.moveUp) pl.Y--;
                if (trl8[0] == TrackAction8.moveDown) pl.Y++;
                if (trl8[0] == TrackAction8.moveLeft) pl.X--;
                if (trl8[0] == TrackAction8.moveRight) pl.X++;
                if (trl8[0] == TrackAction8.moveUpLeft) { pl.Y--; pl.X--; }
                if (trl8[0] == TrackAction8.moveUpRight) { pl.Y--; pl.X++; }
                if (trl8[0] == TrackAction8.moveDownLeft) { pl.Y++; pl.X--; }
                if (trl8[0] == TrackAction8.moveDownRight) { pl.Y++; pl.X++; }
                trl8.RemoveAt(0);
            }

            DrawAll();
            if (trl.Count == 0 && trl8.Count == 0) tmrMove.Stop();
        }

    }
}
